////////////////////////////////////////////////////////////////////////////////////////////////////
//#include "stdafx.h"
#include "IlumpUtils.h"
//include <CColladaModularSkinnedMeshSceneNode.h>
#include "CAdvancedMeshCollision.h"
#include "Core/Commons.h"
#include <float.h>


#ifdef PFEXPORT
	#include <COpenGLTexture.h>
#endif

using namespace irr;
using namespace video;
using namespace scene;

// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Static Methods
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------------------------------
/// @brief Returns the mesh of the node according to the node type
// ----------------------------------------------------------------------------------------------------
IMesh* Utils::GetMesh(ISceneNode* node)
{
	if(!node)
	{
		return 0;
	}
	
	// get node mesh
	IMesh* mesh = 0;
	
	switch(node->getType())
	{
	#ifdef _IRR_COMPILE_WITH_COLLADA_BINARY_LOADER_
		case ESNT_COLLADA_SKIN_MESH:
		case ESNT_COLLADA_MODULAR_SKIN_MESH:
			mesh = ((collada::CSkinnedMeshSceneNode*)node)->getMesh();
		break;

		case ESNT_COLLADA_MESH:
	#endif
		case ESNT_MESH:
		//case ESNT_BATCH_SCENE_NODE:
		//case ESNT_BATCH_GRID_SCENE_NODE:
			mesh = ((IMeshSceneNode*)node)->getMesh();
		break;
	}

	return mesh;
}

// ----------------------------------------------------------------------------------------------------
/// @brief Scans the array of mesh collisions and gets the triangle and point intersection
// ----------------------------------------------------------------------------------------------------
bool Utils::GetMeshCollisionIntersectWithColor(const core::line3d<f32>& ray, 
								CAdvancedMeshCollision** collision_array, s32 count,
								core::vector3df& collisionPoint, core::triangle3df& collisionTriangle,
								u32& color)
{
	bool found = false;

	//core::vector3df point;
	//core::triangle3df triangle;
	//ISceneNode* collisionNode = 0;
	//f32 nearest = FLT_MAX;

	//for(int i = 0; i < count; i++)
	//{
	//	u32 c = 0;
	//	if(collision_array[i]->isRayCollideMesh(ray, point, triangle, c))
	//	{
	//		const f32 tmp = point.getDistanceFromSQ(ray.start);
	//		const f32 tmp2 = point.getDistanceFromSQ(ray.end);
	//		const f32 raylength = ray.getLengthSQ();
	//		if (tmp <= raylength && tmp2 <= raylength && tmp < nearest)
	//		{	
	//			nearest = tmp;
	//			collisionTriangle = triangle;
	//			collisionPoint = point;
	//			found = true;
	//			color = c;
	//		}
	//	}
	//}

	return found;
}

// ----------------------------------------------------------------------------------------------------
/// @brief Scans the array of mesh collisions and gets the triangle and point intersection
// ----------------------------------------------------------------------------------------------------
void Utils::GetMeshCollisionTriangles(core::array<core::triangle3df>& triangles, 
								CAdvancedMeshCollision** collision_array, s32 count)
{
	//triangles.reallocate(2048);
	//for(int i = 0; i < count; i++)
	//{
	//	collision_array[i]->GetTriangles(triangles);
	//}
}


// [HACK] Needed because irrlicht does not compute AABB recursively
//bool Utils::ComputeBoundingBox(ISceneNode* node)
//{
//	node->updateAbsolutePosition();
//	bool hasABox = false;
//	s32 type = node->getType();
//	if (type == ESNT_COLLADA_NODE || type == ESNT_COLLADA_ROOT)
//	{
//		core::aabbox3df& box = const_cast<core::aabbox3df&>(node->getBoundingBox()); // [HACK] write access to read only member
//		box = core::aabbox3df();
//	
//		const core::list<ISceneNode*>& nodes = node->getChildren();
//		core::list<ISceneNode*>::ConstIterator it = nodes.begin();
//		while(it != nodes.end())
//		{
//			ISceneNode* child = *it;
//				
//			if (ComputeBoundingBox(child))
//			{
//				core::aabbox3df childBox = child->getTransformedBoundingBox();
//				core::matrix4 invAbsoluteMtx;
//				node->getAbsoluteTransformation().getInverse(invAbsoluteMtx);
//				invAbsoluteMtx.transformBox(childBox);
//
//				if (!hasABox)
//				{
//					box = childBox;
//				}
//				else
//				{
//					box.addInternalBox(childBox);
//				}
//				hasABox = true;
//			}
//			else
//			{
//				if (!hasABox)
//				{
//					box.reset(child->getPosition().X, child->getPosition().Y, child->getPosition().Z);
//				}
//				else
//				{
//					box.addInternalPoint(child->getPosition());
//				}
//				hasABox = true;
//			}
//			++it;
//		}
//	}
//	else
//	{
//		hasABox = true;
//	}
//	return hasABox;
//}

//
//bool Utils::ComputeBoundingBoxLevelObject(ISceneNode* node)
//{
//	node->updateAbsolutePosition();
//	bool hasABox = false;
//	s32 type = node->getType();
//	if (type == ESNT_COLLADA_NODE || type == ESNT_COLLADA_ROOT)
//	{
//		core::aabbox3df& box = const_cast<core::aabbox3df&>(node->getBoundingBox()); // [HACK] write access to read only member
//		box = core::aabbox3df();
//		return ComputeBoundingBoxLevelObject(node, box, hasABox, node);
//	}
//	else
//	{
//		return true;
//	}
//}
//
//bool Utils::ComputeBoundingBoxLevelObject(ISceneNode* node, core::aabbox3df& box, bool& hasABox, ISceneNode* root )
//{
//	node->updateAbsolutePosition();
//	s32 type = node->getType();
//	if (type == ESNT_COLLADA_NODE || type == ESNT_COLLADA_ROOT)
//	{
//		const core::list<ISceneNode*>& nodes = node->getChildren();
//		core::list<ISceneNode*>::ConstIterator it = nodes.begin();
//		while(it != nodes.end())
//		{
//			ISceneNode* child = *it;
//				
//			if (ComputeBoundingBoxLevelObject(child, box, hasABox, root))
//			{
//				core::aabbox3df childBox = child->getTransformedBoundingBox();
//				
//				core::matrix4 invAbsoluteMtx;
//				root->getAbsoluteTransformation().getInverse(invAbsoluteMtx);
//				invAbsoluteMtx.transformBoxEx(childBox);
//
//				if (!hasABox)
//				{
//					box = childBox;
//				}
//				else
//				{
//					box.addInternalBox(childBox);
//				}
//				hasABox = true;
//				
//			}
//			else
//			{
//				if (!hasABox)
//				{
//					box.reset(child->getPosition().X, child->getPosition().Y, child->getPosition().Z);
//				}
//				else
//				{
//					box.addInternalPoint(child->getPosition());
//				}
//
//				hasABox = true;
//				
//			}
//			++it;
//		}
//	}
//	else if ((type == ESNT_COLLADA_MESH) || (type == ESNT_COLLADA_SKIN_MESH))
//	{
//		hasABox = true;
//	}
//	
//	return hasABox;
//}
//
//// ----------------------------------------------------------------------------------------------------
///// @brief Read all textures pixel data
//// ----------------------------------------------------------------------------------------------------
//void Utils::ReadAllLightmapTextures(ISceneNode* node)
//{
//#ifdef PFEXPORT
//	if(!node)
//	{
//		return;
//	}
//
//	for(int j = 0; j < node->getMaterialCount(); j++)
//	{
//		SMaterial& mat = node->getMaterial(j);
//
//		s32 type = mat.getMaterialType();
//		if(type == EMT_LIGHTMAP 
//			|| type == EMT_LIGHTMAP_LIGHTING
//			|| type == EMT_LIGHTMAP_ADD 
//			|| type == EMT_LIGHTMAP_M2 
//			|| type == EMT_LIGHTMAP_M4
//		)
//		{
//			ITexture* texture = mat.getTexture(1);
//			COpenGLTexture* tex = static_cast<COpenGLTexture*>(texture);
//			if(tex)
//			{				
//				IImage* image = tex->getImage();
//				if(!image)
//				{
//					tex->setIsRenderTarget(true);
//					tex->lock(true);
//					image = tex->getImage();
//				}
//			}
//		}
//	}
//
//	core::list<ISceneNode*>::ConstIterator it = node->getChildren().begin();
//	for (; it != node->getChildren().end(); ++it)
//	{
//		ReadAllLightmapTextures(*it);
//	}
//#endif
//}
//
//// ----------------------------------------------------------------------------------------------------
///// @brief Creates an array of mesh collisions
//// ----------------------------------------------------------------------------------------------------
//void Utils::CreateMeshCollisionArray(ISceneNode* node, CAdvancedMeshCollision** collision_array, s32& count)
//{
//	if(!node)
//	{
//		return;
//	}
//	
//	IMesh* mesh = GetMesh(node);
//
//	if(mesh)
//	{
//		if(collision_array)
//		{
//			collision_array[count] = NEW CAdvancedMeshCollision(node);
//		}
//
//		count++;
//	}
//		
//	core::list<ISceneNode*>::ConstIterator it = node->getChildren().begin();
//	for (; it != node->getChildren().end();)
//	{
//		ISceneNode *n = (*it);
//		it++;
//		CreateMeshCollisionArray(n, collision_array, count);
//	}
//}